from typing import Dict, Any, List, Optional
from datetime import datetime
from bson import ObjectId
from pymongo.collection import Collection
import asyncio
import json
from utils.logger import get_logger
from utils.exceptions import (
    AdapterException,
    ChainException,
    ValidationException
)

logger = get_logger(__name__)

class MultiChainAdaptationGateway:
    """多链适配网关服务 (MAG)
    
    负责:
    1. 多链适配器管理
    2. 链间协议转换
    3. 跨链通信协调
    4. 适配器生命周期管理
    5. 链状态同步
    """
    
    def __init__(self, mongo_db):
        self.db = mongo_db
        self.adapters_collection: Collection = mongo_db.chain_adapters
        self.chain_configs_collection: Collection = mongo_db.chain_configs
        self.cross_chain_transactions_collection: Collection = mongo_db.cross_chain_transactions
        self.adapter_status_collection: Collection = mongo_db.adapter_status
        
        # 适配器注册表
        self.registered_adapters = {}
        self.active_adapters = {}
        
        # 支持的区块链平台
        self.supported_chains = {
            'fisco_bcos': {
                'name': 'FISCO BCOS',
                'version': '3.0+',
                'adapter_class': 'FiscoBcosAdapter',
                'default_config': {
                    'consensus': 'PBFT',
                    'storage': 'RocksDB',
                    'network_type': 'consortium'
                }
            },
            'chainmaker': {
                'name': 'ChainMaker',
                'version': '2.0+',
                'adapter_class': 'ChainMakerAdapter',
                'default_config': {
                    'consensus': 'TBFT',
                    'storage': 'LevelDB',
                    'network_type': 'consortium'
                }
            },
            'jdchain': {
                'name': 'JD Chain',
                'version': '1.6+',
                'adapter_class': 'JdChainAdapter',
                'default_config': {
                    'consensus': 'BFT-SMaRt',
                    'storage': 'RocksDB',
                    'network_type': 'consortium'
                }
            },
            'xuperchain': {
                'name': 'XuperChain',
                'version': '4.0+',
                'adapter_class': 'XuperChainAdapter',
                'default_config': {
                    'consensus': 'XPoA',
                    'storage': 'XuperDB',
                    'network_type': 'public'
                }
            },

            'thanos': {
                'name': 'Thanos Chain',
                'version': '1.0+',
                'adapter_class': 'ThanosAdapter',
                'default_config': {
                    'consensus': 'PBFT',
                    'storage': 'LevelDB',
                    'network_type': 'consortium'
                }
            }
        }
        
        # 创建索引
        self._create_indexes()
        
        # 初始化适配器
        self._initialize_adapters()
    
    def _create_indexes(self):
        """创建数据库索引"""
        try:
            # 适配器集合索引
            self.adapters_collection.create_index("chain_id", unique=True)
            self.adapters_collection.create_index("chain_type")
            self.adapters_collection.create_index("status")
            
            # 链配置集合索引
            self.chain_configs_collection.create_index("chain_id", unique=True)
            self.chain_configs_collection.create_index("chain_type")
            
            # 跨链交易集合索引
            self.cross_chain_transactions_collection.create_index("transaction_id", unique=True)
            self.cross_chain_transactions_collection.create_index("source_chain")
            self.cross_chain_transactions_collection.create_index("target_chain")
            self.cross_chain_transactions_collection.create_index("status")
            self.cross_chain_transactions_collection.create_index("created_at")
            
            # 适配器状态集合索引
            self.adapter_status_collection.create_index("chain_id")
            self.adapter_status_collection.create_index("timestamp")
            
        except Exception as e:
            logger.warning(f"Failed to create indexes: {str(e)}")
    
    def _initialize_adapters(self):
        """初始化适配器"""
        try:
            # 从数据库加载已注册的适配器
            cursor = self.adapters_collection.find({'status': 'active'})
            
            for adapter_doc in cursor:
                chain_id = adapter_doc['chain_id']
                chain_type = adapter_doc['chain_type']
                
                try:
                    # 创建适配器实例
                    adapter = self._create_adapter_instance(chain_type, adapter_doc['config'])
                    self.active_adapters[chain_id] = adapter
                    
                    logger.info(f"Adapter initialized: {chain_id} ({chain_type})")
                    
                except Exception as e:
                    logger.error(f"Failed to initialize adapter {chain_id}: {str(e)}")
                    # 更新适配器状态为错误
                    self.adapters_collection.update_one(
                        {'chain_id': chain_id},
                        {'$set': {'status': 'error', 'error_message': str(e)}}
                    )
            
        except Exception as e:
            logger.error(f"Failed to initialize adapters: {str(e)}")
    
    def _create_adapter_instance(self, chain_type: str, config: Dict[str, Any]):
        """创建适配器实例"""
        from adapters.adapter_factory import AdapterFactory
        
        adapter_factory = AdapterFactory()
        return adapter_factory.get_adapter(chain_type, config)
    
    def register_chain(self, chain_id: str, chain_type: str, config: Dict[str, Any]) -> bool:
        """注册新的区块链"""
        try:
            # 验证链类型
            if chain_type not in self.supported_chains:
                raise AdapterException(f"Unsupported chain type: {chain_type}")
            
            # 检查链ID是否已存在
            existing = self.adapters_collection.find_one({'chain_id': chain_id})
            if existing:
                raise AdapterException(f"Chain already registered: {chain_id}")
            
            # 合并默认配置
            default_config = self.supported_chains[chain_type]['default_config']
            merged_config = {**default_config, **config}
            
            # 验证配置
            self._validate_chain_config(chain_type, merged_config)
            
            # 创建适配器文档
            adapter_doc = {
                'chain_id': chain_id,
                'chain_type': chain_type,
                'chain_name': self.supported_chains[chain_type]['name'],
                'config': merged_config,
                'status': 'inactive',
                'created_at': datetime.utcnow(),
                'updated_at': datetime.utcnow(),
                'error_message': None
            }
            
            # 保存到数据库
            self.adapters_collection.insert_one(adapter_doc)
            
            # 保存链配置
            chain_config_doc = {
                'chain_id': chain_id,
                'chain_type': chain_type,
                'config': merged_config,
                'created_at': datetime.utcnow(),
                'updated_at': datetime.utcnow()
            }
            
            self.chain_configs_collection.insert_one(chain_config_doc)
            
            logger.info(f"Chain registered: {chain_id} ({chain_type})")
            return True
            
        except Exception as e:
            if isinstance(e, AdapterException):
                raise
            logger.error(f"Failed to register chain: {str(e)}")
            raise AdapterException(f"Failed to register chain: {str(e)}")
    
    def _validate_chain_config(self, chain_type: str, config: Dict[str, Any]):
        """验证链配置"""
        required_fields = {
            'fisco_bcos': ['node_url', 'group_id'],
            'chainmaker': ['node_url', 'chain_id', 'org_id'],
            'jdchain': ['gateway_host', 'gateway_port', 'ledger'],
            'xuperchain': ['node_url', 'bcname'],

        }
        
        required = required_fields.get(chain_type, [])
        
        for field in required:
            if field not in config:
                raise ValidationException(f"Missing required config field: {field}")
    
    def activate_chain(self, chain_id: str) -> bool:
        """激活区块链适配器"""
        try:
            # 获取适配器配置
            adapter_doc = self.adapters_collection.find_one({'chain_id': chain_id})
            if not adapter_doc:
                raise AdapterException(f"Chain not found: {chain_id}")
            
            # 创建适配器实例
            adapter = self._create_adapter_instance(
                adapter_doc['chain_type'], 
                adapter_doc['config']
            )
            
            # 测试连接
            if not adapter.test_connection():
                raise AdapterException(f"Failed to connect to chain: {chain_id}")
            
            # 更新状态
            self.adapters_collection.update_one(
                {'chain_id': chain_id},
                {
                    '$set': {
                        'status': 'active',
                        'updated_at': datetime.utcnow(),
                        'error_message': None
                    }
                }
            )
            
            # 添加到活跃适配器
            self.active_adapters[chain_id] = adapter
            
            # 记录状态
            self._record_adapter_status(chain_id, 'activated')
            
            logger.info(f"Chain activated: {chain_id}")
            return True
            
        except Exception as e:
            if isinstance(e, AdapterException):
                raise
            logger.error(f"Failed to activate chain: {str(e)}")
            raise AdapterException(f"Failed to activate chain: {str(e)}")
    
    def deactivate_chain(self, chain_id: str) -> bool:
        """停用区块链适配器"""
        try:
            # 更新数据库状态
            result = self.adapters_collection.update_one(
                {'chain_id': chain_id},
                {
                    '$set': {
                        'status': 'inactive',
                        'updated_at': datetime.utcnow()
                    }
                }
            )
            
            if result.matched_count == 0:
                raise AdapterException(f"Chain not found: {chain_id}")
            
            # 从活跃适配器中移除
            if chain_id in self.active_adapters:
                adapter = self.active_adapters[chain_id]
                adapter.disconnect()
                del self.active_adapters[chain_id]
            
            # 记录状态
            self._record_adapter_status(chain_id, 'deactivated')
            
            logger.info(f"Chain deactivated: {chain_id}")
            return True
            
        except Exception as e:
            if isinstance(e, AdapterException):
                raise
            logger.error(f"Failed to deactivate chain: {str(e)}")
            raise AdapterException(f"Failed to deactivate chain: {str(e)}")
    
    def _record_adapter_status(self, chain_id: str, status: str, details: Dict[str, Any] = None):
        """记录适配器状态"""
        try:
            status_doc = {
                'chain_id': chain_id,
                'status': status,
                'timestamp': datetime.utcnow(),
                'details': details or {}
            }
            
            self.adapter_status_collection.insert_one(status_doc)
            
        except Exception as e:
            logger.error(f"Failed to record adapter status: {str(e)}")
    
    def get_adapter(self, chain_id: str):
        """获取适配器实例"""
        if chain_id not in self.active_adapters:
            raise AdapterException(f"Chain not active: {chain_id}")
        
        return self.active_adapters[chain_id]
    
    def list_chains(self, status: str = None) -> List[Dict[str, Any]]:
        """列出所有链"""
        try:
            query = {}
            if status:
                query['status'] = status
            
            cursor = self.adapters_collection.find(query)
            chains = list(cursor)
            
            # 转换ObjectId
            for chain in chains:
                chain['_id'] = str(chain['_id'])
                chain['created_at'] = chain['created_at'].isoformat()
                chain['updated_at'] = chain['updated_at'].isoformat()
            
            return chains
            
        except Exception as e:
            logger.error(f"Failed to list chains: {str(e)}")
            raise AdapterException(f"Failed to list chains: {str(e)}")
    
    def get_chain_info(self, chain_id: str) -> Dict[str, Any]:
        """获取链信息"""
        try:
            adapter_doc = self.adapters_collection.find_one({'chain_id': chain_id})
            if not adapter_doc:
                raise AdapterException(f"Chain not found: {chain_id}")
            
            # 转换时间戳
            adapter_doc['_id'] = str(adapter_doc['_id'])
            adapter_doc['created_at'] = adapter_doc['created_at'].isoformat()
            adapter_doc['updated_at'] = adapter_doc['updated_at'].isoformat()
            
            # 添加运行时信息
            if chain_id in self.active_adapters:
                adapter = self.active_adapters[chain_id]
                adapter_doc['runtime_info'] = adapter.get_runtime_info()
            
            return adapter_doc
            
        except Exception as e:
            if isinstance(e, AdapterException):
                raise
            logger.error(f"Failed to get chain info: {str(e)}")
            raise AdapterException(f"Failed to get chain info: {str(e)}")
    
    def execute_cross_chain_transaction(self, source_chain: str, target_chain: str, 
                                      transaction_data: Dict[str, Any]) -> str:
        """执行跨链交易"""
        try:
            # 验证源链和目标链
            if source_chain not in self.active_adapters:
                raise ChainException(f"Source chain not active: {source_chain}")
            
            if target_chain not in self.active_adapters:
                raise ChainException(f"Target chain not active: {target_chain}")
            
            # 生成跨链交易ID
            transaction_id = self._generate_cross_chain_transaction_id()
            
            # 创建跨链交易记录
            cross_chain_tx = {
                'transaction_id': transaction_id,
                'source_chain': source_chain,
                'target_chain': target_chain,
                'transaction_data': transaction_data,
                'status': 'pending',
                'created_at': datetime.utcnow(),
                'updated_at': datetime.utcnow(),
                'source_tx_hash': None,
                'target_tx_hash': None,
                'error_message': None
            }
            
            self.cross_chain_transactions_collection.insert_one(cross_chain_tx)
            
            # 异步执行跨链交易
            asyncio.create_task(self._execute_cross_chain_async(transaction_id))
            
            logger.info(f"Cross-chain transaction initiated: {transaction_id}")
            return transaction_id
            
        except Exception as e:
            if isinstance(e, (ChainException, AdapterException)):
                raise
            logger.error(f"Failed to execute cross-chain transaction: {str(e)}")
            raise ChainException(f"Failed to execute cross-chain transaction: {str(e)}")
    
    def _generate_cross_chain_transaction_id(self) -> str:
        """生成跨链交易ID"""
        import hashlib
        timestamp = datetime.utcnow().strftime('%Y%m%d%H%M%S%f')
        hash_value = hashlib.md5(timestamp.encode()).hexdigest()[:8]
        return f"CCTX_{timestamp}_{hash_value}"
    
    async def _execute_cross_chain_async(self, transaction_id: str):
        """异步执行跨链交易"""
        try:
            # 获取交易记录
            tx_doc = self.cross_chain_transactions_collection.find_one(
                {'transaction_id': transaction_id}
            )
            
            if not tx_doc:
                logger.error(f"Cross-chain transaction not found: {transaction_id}")
                return
            
            source_chain = tx_doc['source_chain']
            target_chain = tx_doc['target_chain']
            transaction_data = tx_doc['transaction_data']
            
            # 获取适配器
            source_adapter = self.active_adapters[source_chain]
            target_adapter = self.active_adapters[target_chain]
            
            # 步骤1: 在源链上锁定资产或执行预处理
            source_tx_hash = await source_adapter.prepare_cross_chain_transaction(transaction_data)
            
            # 更新状态
            self.cross_chain_transactions_collection.update_one(
                {'transaction_id': transaction_id},
                {
                    '$set': {
                        'status': 'source_prepared',
                        'source_tx_hash': source_tx_hash,
                        'updated_at': datetime.utcnow()
                    }
                }
            )
            
            # 步骤2: 在目标链上执行交易
            target_tx_hash = await target_adapter.execute_cross_chain_transaction(
                transaction_data, source_tx_hash
            )
            
            # 更新状态
            self.cross_chain_transactions_collection.update_one(
                {'transaction_id': transaction_id},
                {
                    '$set': {
                        'status': 'target_executed',
                        'target_tx_hash': target_tx_hash,
                        'updated_at': datetime.utcnow()
                    }
                }
            )
            
            # 步骤3: 在源链上确认完成
            await source_adapter.confirm_cross_chain_transaction(source_tx_hash, target_tx_hash)
            
            # 最终状态更新
            self.cross_chain_transactions_collection.update_one(
                {'transaction_id': transaction_id},
                {
                    '$set': {
                        'status': 'completed',
                        'updated_at': datetime.utcnow()
                    }
                }
            )
            
            logger.info(f"Cross-chain transaction completed: {transaction_id}")
            
        except Exception as e:
            logger.error(f"Cross-chain transaction failed: {transaction_id} - {str(e)}")
            
            # 更新错误状态
            self.cross_chain_transactions_collection.update_one(
                {'transaction_id': transaction_id},
                {
                    '$set': {
                        'status': 'failed',
                        'error_message': str(e),
                        'updated_at': datetime.utcnow()
                    }
                }
            )
    
    def get_cross_chain_transaction_status(self, transaction_id: str) -> Dict[str, Any]:
        """获取跨链交易状态"""
        try:
            tx_doc = self.cross_chain_transactions_collection.find_one(
                {'transaction_id': transaction_id}
            )
            
            if not tx_doc:
                raise ChainException(f"Cross-chain transaction not found: {transaction_id}")
            
            # 转换时间戳
            tx_doc['_id'] = str(tx_doc['_id'])
            tx_doc['created_at'] = tx_doc['created_at'].isoformat()
            tx_doc['updated_at'] = tx_doc['updated_at'].isoformat()
            
            return tx_doc
            
        except Exception as e:
            if isinstance(e, ChainException):
                raise
            logger.error(f"Failed to get cross-chain transaction status: {str(e)}")
            raise ChainException(f"Failed to get transaction status: {str(e)}")
    
    def get_supported_chains(self) -> Dict[str, Any]:
        """获取支持的区块链平台"""
        return self.supported_chains
    
    def get_adapter_statistics(self) -> Dict[str, Any]:
        """获取适配器统计信息"""
        try:
            # 统计各状态的适配器数量
            pipeline = [
                {
                    '$group': {
                        '_id': '$status',
                        'count': {'$sum': 1}
                    }
                }
            ]
            
            status_stats = list(self.adapters_collection.aggregate(pipeline))
            status_counts = {stat['_id']: stat['count'] for stat in status_stats}
            
            # 统计各类型的适配器数量
            type_pipeline = [
                {
                    '$group': {
                        '_id': '$chain_type',
                        'count': {'$sum': 1}
                    }
                }
            ]
            
            type_stats = list(self.adapters_collection.aggregate(type_pipeline))
            type_counts = {stat['_id']: stat['count'] for stat in type_stats}
            
            # 跨链交易统计
            cross_chain_stats = self._get_cross_chain_statistics()
            
            return {
                'total_adapters': self.adapters_collection.count_documents({}),
                'active_adapters': len(self.active_adapters),
                'status_breakdown': status_counts,
                'type_breakdown': type_counts,
                'cross_chain_statistics': cross_chain_stats,
                'supported_chain_types': len(self.supported_chains)
            }
            
        except Exception as e:
            logger.error(f"Failed to get adapter statistics: {str(e)}")
            raise AdapterException(f"Failed to get statistics: {str(e)}")
    
    def _get_cross_chain_statistics(self) -> Dict[str, Any]:
        """获取跨链交易统计"""
        try:
            # 总交易数
            total_transactions = self.cross_chain_transactions_collection.count_documents({})
            
            # 按状态统计
            status_pipeline = [
                {
                    '$group': {
                        '_id': '$status',
                        'count': {'$sum': 1}
                    }
                }
            ]
            
            status_stats = list(self.cross_chain_transactions_collection.aggregate(status_pipeline))
            status_counts = {stat['_id']: stat['count'] for stat in status_stats}
            
            # 最近24小时的交易数
            recent_time = datetime.utcnow() - timedelta(hours=24)
            recent_transactions = self.cross_chain_transactions_collection.count_documents({
                'created_at': {'$gte': recent_time}
            })
            
            return {
                'total_transactions': total_transactions,
                'recent_24h_transactions': recent_transactions,
                'status_breakdown': status_counts,
                'success_rate': status_counts.get('completed', 0) / total_transactions * 100 if total_transactions > 0 else 0
            }
            
        except Exception as e:
            logger.error(f"Failed to get cross-chain statistics: {str(e)}")
            return {'error': str(e)}


class MockAdapter:
    """模拟适配器类"""
    
    def __init__(self, chain_type: str, config: Dict[str, Any]):
        self.chain_type = chain_type
        self.config = config
        self.connected = False
    
    def test_connection(self) -> bool:
        """测试连接"""
        # 模拟连接测试
        self.connected = True
        return True
    
    def disconnect(self):
        """断开连接"""
        self.connected = False
    
    def get_runtime_info(self) -> Dict[str, Any]:
        """获取运行时信息"""
        return {
            'connected': self.connected,
            'chain_type': self.chain_type,
            'last_block_height': 12345,
            'peer_count': 4,
            'sync_status': 'synced'
        }
    
    async def prepare_cross_chain_transaction(self, transaction_data: Dict[str, Any]) -> str:
        """准备跨链交易"""
        # 模拟异步操作
        await asyncio.sleep(1)
        return f"source_tx_hash_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}"
    
    async def execute_cross_chain_transaction(self, transaction_data: Dict[str, Any], source_tx_hash: str) -> str:
        """执行跨链交易"""
        # 模拟异步操作
        await asyncio.sleep(2)
        return f"target_tx_hash_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}"
    
    async def confirm_cross_chain_transaction(self, source_tx_hash: str, target_tx_hash: str):
        """确认跨链交易"""
        # 模拟异步操作
        await asyncio.sleep(1)
        return True